#include <cstdlib>
#include <assert.h>
#include <cstdio>
#include <stdint.h>
#include <cstring>

#ifdef __RV32__
typedef uint32_t rtlreg_t;
typedef uint32_t paddr_t;
#else
typedef uint64_t rtlreg_t;
typedef uint64_t paddr_t;
#endif

// 128MB
#define RAMSIZE (128 * 1024 * 1024)
// byte
static paddr_t ram[ RAMSIZE / sizeof(paddr_t)];

static long img_size = 0;
void* get_img_start() { return &ram[0]; }
long get_img_size() { return img_size; }

void init_ram(const char *img) {
  assert(img != NULL);
  FILE *fp = fopen(img, "rb");
  if (fp == NULL) {
    printf("Can not open '%s'\n", img);
    assert(0);
  }

  printf("The image is %s\n", img);

  fseek(fp, 0, SEEK_END);
  img_size = ftell(fp);

  fseek(fp, 0, SEEK_SET);
  int ret = fread(ram, img_size, 1, fp);
  assert(ret == 1);
  fclose(fp);

}

bool instcheck(uint64_t pc, uint64_t inst){
    uint64_t word = ram[(pc & 0x7ffffff8) >> 3];
    uint32_t fetch = word >> ((pc & 0x7) << 3);
    return fetch == inst;
}

extern "C" void ram_helper(
    paddr_t rIdx, paddr_t *rdata, paddr_t wIdx, paddr_t wdata, paddr_t wmask, uint8_t wen) {
  *rdata = ram[rIdx];
  if (wen) {
    ram[wIdx] = (ram[wIdx] & ~wmask) | (wdata & wmask);
  }
}

// extern "C" void ram_read(paddr_t rIdx, paddr_t *rdata)
// {
//     *rdata = ram[rIdx];
// }

// extern "C" void ram_write(paddr_t wIdx, paddr_t wdata, paddr_t wmask, uint8_t wen)
// {
//     if (wen) {
//         ram[wIdx] = (ram[wIdx] & ~wmask) | (wdata & wmask);
//         //printf("ram_write wIdx=%lx, wdata=%lx, wmask=%lx\n", wIdx, wdata, wmask);
//     }
// }
